package com.aliware.tianchi;

import org.apache.dubbo.rpc.Invoker;

import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Description:
 * Date: 19-7-1
 *
 * @author ujued
 */
class Selector {
    private static final WeightAdjust<Invoker> WEIGHT_ADJUST = new WeightAdjust<>();
    private static AtomicBoolean invokersReady = new AtomicBoolean(false);
    private static List<Invoker> invokers;
    private static ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);
    private static AtomicInteger counter = new AtomicInteger(0);
    private static final Map<String, Integer> w = new HashMap<>();

    static {
        w.put("20880", 200);
        w.put("20870", 450);
        w.put("20890", 650);
    }

    static void adjustWeight(String invokerId, Integer weight) {
        if (Objects.isNull(invokers)) {
            return;
        }
        for (Invoker invoker : invokers) {
            if (invokerId.equals(String.valueOf(invoker.getUrl().getPort()))) {
                WEIGHT_ADJUST.adjustWeight(invoker, weight);
            }
        }
    }

    @SuppressWarnings("unchecked")
    static <T> Invoker<T> select(List<Invoker<T>> invokers) {
        // 1. 所有Providers, 初始化权重
        if (invokersReady.compareAndSet(false, true)) {
            Selector.invokers = new ArrayList<>(invokers);
            Map<Invoker, Integer> init = new HashMap<>();
            invokers.forEach(invoker -> init.put(invoker, w.getOrDefault(String.valueOf(invoker.getUrl().getPort()), 100)));
            WEIGHT_ADJUST.init(init);

            executorService.scheduleWithFixedDelay(() -> {
                int val = counter.getAndIncrement();
                if (val == 0) {
                    Selector.adjustWeight("20880", 100);
                    Selector.adjustWeight("20870", 350);
                    Selector.adjustWeight("20890", 400);
                } else if (val == 1) {
                    Selector.adjustWeight("20880", 150);
                    Selector.adjustWeight("20870", 380);
                    Selector.adjustWeight("20890", 500);
                } else {
                    Selector.adjustWeight("20880", 180);
                    Selector.adjustWeight("20870", 410);
                    Selector.adjustWeight("20890", 600);
                }
            }, 35, 15, TimeUnit.SECONDS);
        }

        // 2. 按权重负载
        return Optional.ofNullable(WEIGHT_ADJUST.selectByWeight()).orElse(invokers.get(0));
    }

    static String weightInfo() {
        return WEIGHT_ADJUST.toString();
    }
}
